#include <sum_gpio.h>
#include <sum_rcu.h>
#include <sum_usart.h>
#include <util_abs.h>
#include <util_max_min_i32.h>
#include <util_max_min_u32.h>
#include <util_trans.h>

#define APB2_FREQ_DEFAULT 8000000
#define LOW_ZERO_AMOUNT 24

// RCU中将GPIOA和USART0上电
static void _enable_gpioa_usart0(void) {
	rcu_apb2_s apb2 = {
		.apb2_0_7.GPIOA = 1,
		.apb2_8_15.USART0 = 1,
	};
	rcu_apb2_en_di(apb2);
}

// 配置A9为AF输出，A10为浮空输入。
static void _setup_gpafio(void) {
	gpio_ctl_8_15_s ctl = {
		// A9的配置：低速输出、AF、推挽
		.pin9_ctl = GPIO_OUT_AF_PP_2MHZ,
		// A10的配置：输入、浮空
		.pin10_ctl = GPIO_IN_FLOAT,
	};
	gpio_setup_pin_8_15(GPIOA_Q, ctl);
}

// 使能USART0本身，以及其发送功能。
static void _enable_usart0_send(void) {
	usart_ctl0_expl_s ctl0 = {
		.trans_en = 1,
		.usart_en = 1,
	};
	usart_setup_0(USART0_Q, ctl0);
}

// 向串口阻塞发送1字节的函数，也是trans_write系列函数的参数。
static void _send(u32_s byte) {
	usart_wb_byte(USART0_Q, byte);
}

static u32_s _verify_diff(i32_s n1, i32_s n2) {
	u64_s real_diff_u64;
	if (n1 > n2) {
		real_diff_u64 = n1 - n2;
	} else {
		real_diff_u64 = n2 - n1;
	}
	u32_s real_diff_u32 = real_diff_u64;
	if (((u64_s)real_diff_u32) != real_diff_u64) {
		return 1;
	}

	u32_s sm_diff = sm_abs_diff(n1, n2);
	if (sm_diff != real_diff_u32) {
		trans_write_str("Error! Diff of ", _send);
		trans_write_idec(n1, _send);
		trans_write_str(" and ", _send);
		trans_write_idec(n2, _send);
		trans_write_str(" is ", _send);
		trans_write_udec(real_diff_u32, _send);
		trans_write_str(", but sm func get ", _send);
		trans_write_udec(sm_diff, _send);
		trans_write_str(".\n", _send);
		return 0;
	} else {
		return 1;
	}
}

static u32_s _verify_max_min_i32(i32_s n1, i32_s n2) {
	i32_s real_max, real_min;
	if (n1 >= n2) {
		real_max = n1;
		real_min = n2;
	} else {
		real_max = n2;
		real_min = n1;
	}

	max_min_i32_t sm_max_min = sm_max_min_i32(n1, n2);
	u32_s result = 1;
	if (sm_max_min.max != real_max) {
		result = 0;
		trans_write_str("Error! Max of signed ", _send);
		trans_write_idec(n1, _send);
		trans_write_str(" and ", _send);
		trans_write_idec(n2, _send);
		trans_write_str(" is ", _send);
		trans_write_idec(real_max, _send);
		trans_write_str(", but sm func get ", _send);
		trans_write_idec(sm_max_min.max, _send);
		trans_write_str(".\n", _send);
	}
	if (sm_max_min.min != real_min) {
		result = 0;
		trans_write_str("Error! Min of ", _send);
		trans_write_idec(n1, _send);
		trans_write_str(" and ", _send);
		trans_write_idec(n2, _send);
		trans_write_str(" is ", _send);
		trans_write_idec(real_min, _send);
		trans_write_str(", but sm func get ", _send);
		trans_write_idec(sm_max_min.min, _send);
		trans_write_str(".\n", _send);
	}
	return result;
}

static u32_s _verify_max_min_u32(u32_s n1, u32_s n2) {
	i32_s real_max, real_min;
	if (n1 >= n2) {
		real_max = n1;
		real_min = n2;
	} else {
		real_max = n2;
		real_min = n1;
	}

	max_min_u32_t sm_max_min = sm_max_min_u32(n1, n2);
	u32_s result = 1;
	if (sm_max_min.max != real_max) {
		result = 0;
		trans_write_str("Error! Max of unsigned ", _send);
		trans_write_udec(n1, _send);
		trans_write_str(" and ", _send);
		trans_write_udec(n2, _send);
		trans_write_str(" is ", _send);
		trans_write_udec(real_max, _send);
		trans_write_str(", but sm func get ", _send);
		trans_write_udec(sm_max_min.max, _send);
		trans_write_str(".\n", _send);
	}
	if (sm_max_min.min != real_min) {
		result = 0;
		trans_write_str("Error! Min of ", _send);
		trans_write_udec(n1, _send);
		trans_write_str(" and ", _send);
		trans_write_udec(n2, _send);
		trans_write_str(" is ", _send);
		trans_write_udec(real_min, _send);
		trans_write_str(", but sm func get ", _send);
		trans_write_udec(sm_max_min.min, _send);
		trans_write_str(".\n", _send);
	}
	return result;
}

// 检查各函数。若发现错误，会输出错误信息。
static void _verify(void) {
	trans_write_str("Verify sm_abs_diff(), sm_max_min_i32(), sm_max_min_u32().\n", _send);
	i32_s i = 0;
	do {
		i32_s j = 0;
		do {
			u32_s diff_result = _verify_diff(i, j);
			if (!diff_result) {
				return;
			}
			u32_s diff_max_min_i32 = _verify_max_min_i32(i, j);
			if (!diff_max_min_i32) {
				return;
			}
			u32_s diff_max_min_u32 = _verify_max_min_u32(i, j);
			if (!diff_max_min_u32) {
				return;
			}

			u32_s j_u32 = j;
			j_u32 += (1 << LOW_ZERO_AMOUNT);
			j = j_u32;
		} while (j != 0);

		u32_s i_u32 = i;
		i_u32 += (1 << LOW_ZERO_AMOUNT);
		i = i_u32;
	} while (i != 0);
	trans_write_str("All right!\n", _send);
}

__attribute__((noreturn, section(".MAIN"))) void user_main(void) {
	// 没有全局变量，不需要scatter_load。
	// mem_scatter_load();
	_enable_gpioa_usart0();
	_setup_gpafio();
	usart_set_baud_rate(USART0_Q, 115200, APB2_FREQ_DEFAULT);
	_enable_usart0_send();

	_verify();
	while (1)
		;
}
